#define ZOPTIMIZE_ABS
#define ZOPTIMIZE_SIGN
#define ZOPTIMIZE_MINMAX
#define ZOPTIMIZE_SETCLEARBIT
#include <UnitTest++.h>
#include <Math/Math.hpp>
#include <Utility/Tools.hpp>

using namespace zzz;

SUITE(MathOptTest)
{
  TEST(AbsOptIntTest)
  {
    int x=0;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-0;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=1;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-1;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=MAX_INT;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-MAX_INT;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
  }
  TEST(AbsOptShortTest)
  {
    short x=0;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-0;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=1;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-1;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=MAX_SHORT;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-MAX_SHORT;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
  }
  TEST(AbsOptCharTest)
  {
    char x=0;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-0;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=1;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-1;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=MAX_CHAR;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
    x=-MAX_CHAR;
    CHECK_EQUAL(std::abs(x),Abs(x));
    CHECK_EQUAL((x>=0)?1:-1,Sign(x));
  }

  TEST(MinMaxOptIntTest)
  {
    int x=0,y=1;
    CHECK_EQUAL(std::max(x,y),Max(x,y));
    CHECK_EQUAL(std::min(x,y),Min(x,y));
    y=-1;
    CHECK_EQUAL(std::max(x,y),Max(x,y));
    CHECK_EQUAL(std::min(x,y),Min(x,y));
    x=1;
    CHECK_EQUAL(std::max(x,y),Max(x,y));
    CHECK_EQUAL(std::min(x,y),Min(x,y));
    x=MAX_INT/2;
    CHECK_EQUAL(std::max(x,y),Max(x,y));
    CHECK_EQUAL(std::min(x,y),Min(x,y));
    y=-MAX_INT/2;
    CHECK_EQUAL(std::max(x,y),Max(x,y));
    CHECK_EQUAL(std::min(x,y),Min(x,y));
  }

  TEST(SetClearBitOptTest)
  {
    int x=0, y=1<<3, x2=x;
    x2|=y;
    SetClearBit(x,y,true);
    CHECK_EQUAL(x2,x);
    x2&=~y;
    SetClearBit(x,y,false);
    CHECK_EQUAL(x2,x);

    x=MAX_INT;x2=x;
    x2|=y;
    SetClearBit(x,y,true);
    CHECK_EQUAL(x2,x);
    x2&=~y;
    SetClearBit(x,y,false);
    CHECK_EQUAL(x2,x);
  }

  TEST(SetClearBitOptUTest)
  {
    zuint x=0, y=1<<3, x2=x;
    x2|=y;
    SetClearBit(x,y,true);
    CHECK_EQUAL(x2,x);
    x2&=~y;
    SetClearBit(x,y,false);
    CHECK_EQUAL(x2,x);

    x=MAX_INT;x2=x;
    x2|=y;
    SetClearBit(x,y,true);
    CHECK_EQUAL(x2,x);
    x2&=~y;
    SetClearBit(x,y,false);
    CHECK_EQUAL(x2,x);
  }

}
